package com.own.component.util.excel.util.read;

import com.alibaba.fastjson2.JSONObject;
import com.own.component.common.util.list.ListUtil;
import com.own.component.util.excel.exception.ExcelException;
import com.own.component.util.excel.util.read.base.AbstractExcelRead;
import com.own.component.util.excel.util.read.config.ExcelReadLineConfig;
import com.own.component.util.excel.util.read.function.resolve.ResolveFunction;
import com.own.component.util.excel.util.read.function.resolve.ResolveSimpleFunction;
import com.own.component.util.excel.util.read.method.RowMethod;
import com.own.component.util.excel.util.read.method.SheetMethod;
import com.own.component.util.excel.util.read.model.ResolveData;
import com.own.component.util.excel.util.read.model.ResolveFileModel;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.usermodel.Sheet;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * ExcelRead
 *
 * @author chenxueli
 * @date 2022-06-15 03:14:15
 */
@Slf4j
@NoArgsConstructor
public class ExcelRead<T> extends AbstractExcelRead<T, ResolveFunction<T>, ExcelReadLineConfig<T>> {

    // jsonObject对象信息
    public final static ResolveSimpleFunction<JSONObject> TO_JSON_OBJECT = data -> data;
    // map string对象信息
    public final static ResolveSimpleFunction<Map<String, String>> TO_MAP_STRING = data -> {
        var map = new HashMap<String, String>();
        data.forEach((key, value) -> map.put(key, value.toString()));
        return map;
    };
    // map object对象信息
    public final static ResolveSimpleFunction<Map<String, Object>> TO_MAP_OBJECT = HashMap::new;

    /**
     * 读取excel内容
     *
     * @param fileModel       文件信息
     * @param resolveFunction 解析数据的方法
     * @return 解析后的内容信息
     */
    @Override
    public List<T> read(ResolveFileModel fileModel, ResolveFunction<T> resolveFunction) {
        // 获取工作表
        var sheet = getSheet(fileModel.getInputStream());
        // 开始读取数据
        return read(sheet, resolveFunction);
    }

    /**
     * 获取表格的数据对象
     *
     * @param sheet           工作表
     * @param resolveFunction 解析方法
     * @return 列表信息
     */
    private List<T> read(Sheet sheet, ResolveFunction<T> resolveFunction) {
        // 获取当前的配置信息
        var config = getCurrentConfig();
        // 获取对应的字段信息
        var fieldList = config.getFieldMethod().apply(sheet.getRow(config.getFieldLine()));
        // 解析文件
        return read(sheet, config.getDataLine(), fieldList, resolveFunction);
    }

    /**
     * 读取表格
     *
     * @param sheet           工作表
     * @param start           数据开始行
     * @param fieldList       批注列表
     * @param resolveFunction 解析方法
     * @return 列表信息
     */
    private List<T> read(Sheet sheet, int start, final List<String> fieldList, ResolveFunction<T> resolveFunction) {
        var config = getCurrentConfig();
        // 字段的索引位置
        var fieldIndexList = ListUtil.listNonValueIndex(fieldList, Function.identity());
        // 判断是否有索引信息
        if (fieldIndexList.isEmpty()) {
            return new ArrayList<>();
        }
        var length = sheet.getLastRowNum();
        var resultList = new ArrayList<ResolveData<T>>();
        var dataList = new ArrayList<T>();
        var readDataIndex = 0;
        for (int i = start; i <= length; ++i) {
            // 判断是否读到底了
            if (readDataIndex >= config.getReadLine()) {
                break;
            }
            var rowData = SheetMethod.listRowValue(sheet, i, config);
            if (rowData.size() == 0) {
                continue;
            }
            // 数值与序号对应
            var object = new JSONObject();
            fieldIndexList.forEach(index -> object.put(fieldList.get(index), rowData.size() < index + 1 ? "" : rowData.get(index)));
            // 存放消息的列表
            var messageList = new ArrayList<String>();
            // 解析后的数据
            var data = resolveFunction.run(object, dataList, messageList);
            var resolve = new ResolveData<>(data, i, messageList);
            dataList.add(data);
            resultList.add(resolve);
            readDataIndex++;
        }
        // 读取全部完成，抛出异常
        if (resultList.stream().anyMatch(ResolveData::isFail)) {
            var message = resultList.stream()
                    // 过滤失败的数据
                    .filter(ResolveData::isFail)
                    .map(resolveData -> "第" + resolveData.getLine() + "行 " + String.join(",", resolveData.getMessageList()))
                    .collect(Collectors.joining("\n"));
            throw new ExcelException(String.format("文件读取异常：%s", message));
        }
        return resultList.stream().map(ResolveData::getData).collect(Collectors.toList());
    }

    /**
     * 字段值使用单元格信息
     *
     * @return this
     */
    public ExcelRead<T> fieldUseCellValue() {
        var config = getCurrentConfig();
        config.setFieldMethod(item -> RowMethod.listRowValue(item, config));
        return this;
    }

    /**
     * 字段值使用备注信息
     *
     * @return this
     */
    public ExcelRead<T> fieldUseCellComment() {
        var config = getCurrentConfig();
        config.setFieldMethod(item -> RowMethod.listRowComment(item, config));
        return this;
    }

    /**
     * 获取默认的配置信息
     *
     * @return 默认的配置信息
     */
    @Override
    protected ExcelReadLineConfig<T> getDefaultConfig() {
        return new ExcelReadLineConfig<>();
    }

}
